
/*
 * Copyright (C) 2008-2009 Archie L. Cobbs. All rights reserved.
 *
 * $Id: AbstractSchemaUpdate.java 377 2010-03-11 20:50:18Z archie.cobbs $
 */

package org.dellroad.sidekar.schema.change;

import org.dellroad.sidekar.Sidekar;
import org.dellroad.sidekar.schema.SchemaModificationException;
import org.dellroad.sidekar.schema.model.EntityModel;
import org.dellroad.sidekar.schema.model.FieldModel;
import org.dellroad.sidekar.schema.model.IndexModel;
import org.dellroad.sidekar.schema.model.SchemaModel;

/**
 * Common superclass for Sidekar {@link SchemaChange} objects, which represent schema mutations.
 */
public abstract class SchemaChange {

    // package private
    SchemaChange() {
    }

    /**
     * Get a human-readable description of this change.
     */
    public abstract String getDescription();

    /**
     * Verify this change is valid when applied to the given {@link SchemaModel}.
     *
     * <p>
     * This performs all of the static checks for things like invalid names,
     * adding duplicate or conflicting items, removing non-existing items, etc.
     * </p>
     *
     * @param schemaModel model to validate this change against; will not be modified
     * @throws SchemaModificationException if this instance is not valid for {@code schemaModel}
     */
    public abstract void checkValidFor(SchemaModel schemaModel);

    /**
     * Implements the {@link SchemaChangeSwitch} visitor pattern.
     */
    public abstract void visit(SchemaChangeSwitch schemaChangeSwitch);

// Internal checks

    EntityModel checkEntityExists(SchemaModel schemaModel, String name) {
        EntityModel entityModel = schemaModel.getEntityModels().get(name);
        if (entityModel == null)
            throw new SchemaModificationException("no such entity `" + name + "'");
        return entityModel;
    }

    void checkEntityNotExists(SchemaModel schemaModel, String name) {
        if (schemaModel.getEntityModels().containsKey(name))
            throw new SchemaModificationException("an entity named `" + name + "' already exists");
    }

    FieldModel checkFieldExists(EntityModel entityModel, String name) {
        FieldModel fieldModel = entityModel.getFieldModels().get(name);
        if (fieldModel == null)
            throw new SchemaModificationException("no such field `" + name + "' in " + entityModel);
        return fieldModel;
    }

    IndexModel checkIndexExists(EntityModel entityModel, String name) {
        IndexModel indexModel = entityModel.getIndexModels().get(name);
        if (indexModel == null)
            throw new SchemaModificationException("no such index `" + name + "' in " + entityModel);
        return indexModel;
    }

    void checkValidEntityName(String name) {
        try {
            Sidekar.checkValidEntityName(name);
        } catch (IllegalArgumentException e) {
            throw new SchemaModificationException(e.getMessage());
        }
    }

    void checkValidFieldName(String name) {
        try {
            Sidekar.checkValidFieldName(name);
        } catch (IllegalArgumentException e) {
            throw new SchemaModificationException(e.getMessage());
        }
    }

    void checkValidIndexName(String name) {
        try {
            Sidekar.checkValidIndexName(name);
        } catch (IllegalArgumentException e) {
            throw new SchemaModificationException(e.getMessage());
        }
    }
}

